package com.thh.redisstudy.service;

import com.thh.redisstudy.RedisService;
import com.thh.redisstudy.entity.ScoreFlow;
import com.thh.redisstudy.entity.SysUser;
import com.thh.redisstudy.entity.UserScore;
import com.thh.redisstudy.entity.UserScoreExample;
import com.thh.redisstudy.mapper.ScoreFlowMapper;
import com.thh.redisstudy.mapper.SysUserMapper;
import com.thh.redisstudy.mapper.UserScoreMapper;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author kaizen
 * @since 2019-07-20
 **/
@Service
public class RangingService implements InitializingBean {

    private static final String RANK_NAME = "user_score";

    private static final String SALE_SCORE = "sale_score_rank:";

    @Autowired
    private RedisService redisService;

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private ScoreFlowMapper scoreFlowMapper;

    @Autowired
    private UserScoreMapper userScoreMapper;


    public void rankAdd(Integer uid, Integer score) {
        redisService.zAdd(RANK_NAME, uid, score);
    }

    public void increSocre(Integer uid, Integer score) {

        redisService.incrementScore(RANK_NAME, uid, score);
    }

    public Long rankNum(Integer uid) {
        return redisService.zRank(RANK_NAME, uid);
    }

    public Long score(Integer uid) {
        Long score = redisService.zSetScore(RANK_NAME, uid).longValue();
        return score;
    }

    public Set<ZSetOperations.TypedTuple<Object>> rankWithScore(Integer start, Integer end) {
        return redisService.zRankWithScore(RANK_NAME, start, end);
    }


    /**
     * 数据预热
     */
    public void rankSaleAdd() {
        UserScoreExample example = new UserScoreExample();
        example.setOrderByClause("id desc");
        List<UserScore> userScores = userScoreMapper.selectByExample(example);
        if (!userScores.isEmpty()) {
            userScores.forEach(userScore -> {
                String key = userScore.getUserId() + ":" + userScore.getName();
                redisService.zAdd(SALE_SCORE, key, userScore.getUserScore());
            });
        }

    }


    /**
     * 添加用户积分
     *
     * @param uid
     * @param score
     */
    public void incrSaleScore(Integer uid, Integer score) {
        SysUser user = userMapper.selectByPrimaryKey(uid);
        if (user == null) {
            return;
        }
        Long socreLong = Long.parseLong(score + "");
        String name = user.getUserName();
        String key = uid + ":" + name;
        scoreFlowMapper.insertSelective(new ScoreFlow(socreLong, uid, name));
        userScoreMapper.insertSelective(new UserScore(uid, socreLong, name));
        redisService.incrementScore(SALE_SCORE, key, score);
    }


    public Map<String, Object> userRank(Integer uid, String name) {
        Map<String, Object> retMap = new LinkedHashMap<>();
        String key = uid + ":" + name;
        Integer rank = redisService.zRank(SALE_SCORE, key).intValue();
        Long score = redisService.zSetScore(SALE_SCORE, key).longValue();
        retMap.put("userId", uid);
        retMap.put("score", score);
        retMap.put("rank", rank);
        return retMap;
    }


    public List<Map<String, Object>> reverseZRankWithRank(long start, long end) {
        Set<ZSetOperations.TypedTuple<Object>> setObj = redisService.reverseZRankWithRank(SALE_SCORE, start, end);
        List<Map<String, Object>> mapList = setObj.stream().map(objectTypedTuple -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("userId", objectTypedTuple.getValue().toString().split(":")[0]);
            map.put("userName", objectTypedTuple.getValue().toString().split(":")[1]);
            map.put("score", objectTypedTuple.getScore());
            return map;
        }).collect(Collectors.toList());
        return mapList;
    }

    public List<Map<String, Object>> saleRankWithScore(Integer start, Integer end) {
        Set<ZSetOperations.TypedTuple<Object>> setObj = redisService.reverseZRankWithScore(SALE_SCORE, start, end);
        List<Map<String, Object>> mapList = setObj.stream().map(objectTypedTuple -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("userId", objectTypedTuple.getValue().toString().split(":")[0]);
            map.put("userName", objectTypedTuple.getValue().toString().split(":")[1]);
            map.put("score", objectTypedTuple.getScore());
            return map;
        }).collect(Collectors.toList());
        return mapList;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("======enter init bean=======");
        this.rankSaleAdd();
    }
}
